/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-03-23     Y       the first version
 */
#include "rgb_led.h"
#include "display_demo.h"
#include "animation_code.h"
#include "key_process.h"

#include "math.h"
#include "stdlib.h"

void SetPixel(int x, int y, int R,int G,int B)
{
    if(x < 0 || x >= MATRIX_WIDTH || y < 0 || y >= MATRIX_HEIGHT)
        return ;

    int index = x * MATRIX_HEIGHT + y;

    Display_PWM[index][0] = R;
    Display_PWM[index][1] = G;
    Display_PWM[index][2] = B;
}

#define max(a,b) ( ((a)>(b)) ? (a):(b) )
#define min(a,b) ( ((a)>(b)) ? (b):(a) )

void Rotate (int x, int y, float angle,
             float* new_x, float* new_y)
{
    *new_x = x * cosf (angle) - y * sinf (angle);
    *new_y = x * sinf (angle) + y * cosf (angle);
}

uint8_t scale_col (int val, int lo, int hi)
{
    if (val < lo) return 0;

    if (val > hi) return 255;

    return 255 * (val - lo) / (hi - lo);
}

void Display_Demo0()
{
    const int cent_x = MATRIX_WIDTH / 2;
    const int cent_y = MATRIX_HEIGHT / 2;

// The square to rotate (inner square + black frame) needs to cover the
// whole area, even if diagnoal. Thus, when rotating, the outer pixels from
// the previous frame are cleared.
    const int rotate_square = min (MATRIX_WIDTH, MATRIX_HEIGHT) * 1.41;
    const int min_rotate = cent_x - rotate_square / 2;
    const int max_rotate = cent_x + rotate_square / 2;

// The square to display is within the visible area.
    const int display_square = min (MATRIX_WIDTH, MATRIX_HEIGHT) * 0.9;
    const int min_display = cent_x - display_square / 2;
    const int max_display = cent_x + display_square / 2;

    const float deg_to_rad = 2 * 3.14159265 / 360;
    int rotation = 0;

    for (int x = min_rotate; x < max_rotate; ++x)
    {
        for (int y = min_rotate; y < max_rotate; ++y)
        {
            float rot_x, rot_y;
            Rotate (x - cent_x, y - cent_x,
                    deg_to_rad * rotation, &rot_x, &rot_y);

            if (x >= min_display && x < max_display &&
                    y >= min_display && y < max_display)   // within display square
            {
                SetPixel (rot_x + cent_x, rot_y + cent_y,
                                    scale_col (x, min_display, max_display),
                                    255 - scale_col (y, min_display, max_display),
                                    scale_col (y, min_display, max_display));
            }
            else
            {
                // black frame.
                SetPixel (rot_x + cent_x, rot_y + cent_y, 0, 0, 0);
            }
        }
    }
    while(get_demo_index() == 0)
        rt_thread_mdelay(100);
}

void Display_Demo1()
{
    const int cent_x = MATRIX_WIDTH / 2;
    const int cent_y = MATRIX_HEIGHT / 2;

// The square to rotate (inner square + black frame) needs to cover the
// whole area, even if diagnoal. Thus, when rotating, the outer pixels from
// the previous frame are cleared.
    const int rotate_square = min (MATRIX_WIDTH, MATRIX_HEIGHT) * 1.41;
    const int min_rotate = cent_x - rotate_square / 2;
    const int max_rotate = cent_x + rotate_square / 2;

// The square to display is within the visible area.
    const int display_square = min (MATRIX_WIDTH, MATRIX_HEIGHT) * 0.7;
    const int min_display = cent_x - display_square / 2;
    const int max_display = cent_x + display_square / 2;

    const float deg_to_rad = 2 * 3.14159265 / 360;
    int rotation = 0;

    while(get_demo_index() == 1)
    {
        ++rotation;

        rt_thread_mdelay(100);

        rotation %= 360;

        for (int x = min_rotate; x < max_rotate; ++x)
        {
            for (int y = min_rotate; y < max_rotate; ++y)
            {
                float rot_x, rot_y;
                Rotate (x - cent_x, y - cent_x,
                        deg_to_rad * rotation, &rot_x, &rot_y);

                if (x >= min_display && x < max_display &&
                        y >= min_display && y < max_display)   // within display square
                {
                    SetPixel (rot_x + cent_x, rot_y + cent_y,
                                        scale_col (x, min_display, max_display),
                                        255 - scale_col (y, min_display, max_display),
                                        scale_col (y, min_display, max_display));
                }
                else
                {
                    // black frame.
                    SetPixel (rot_x + cent_x, rot_y + cent_y, 0, 0, 0);
                }
            }
        }
    }
}

void Display_Demo2 (void)
{
    const uint8_t* gImage_p = gImage_111;
    int PicCount = 0, count = 1;
    int total_point = sizeof (gImage_111);
    int i, a, j = 0;
    uint8_t last_index=get_image_index();

    while(get_demo_index() == 2)
    {
        for (i = 0; i < 16; i++)
        {
            for (a = 0; a < 16; a++)
            {
                Display_PWM[a * 2 + i * 16 * 2 * 2][0] = gImage_p[j];
                Display_PWM[a * 2 + i * 16 * 2 * 2 + 1][0] = gImage_p[j];
                Display_PWM[a * 2 + i * 16 * 2 * 2 + 32][0] = gImage_p[j];
                Display_PWM[a * 2 + i * 16 * 2 * 2 + 32 + 1][0] = gImage_p[j];

                Display_PWM[a * 2 + i * 16 * 2 * 2][1] = gImage_p[j + 1];
                Display_PWM[a * 2 + i * 16 * 2 * 2 + 1][1] = gImage_p[j + 1];
                Display_PWM[a * 2 + i * 16 * 2 * 2 + 32][1] = gImage_p[j + 1];
                Display_PWM[a * 2 + i * 16 * 2 * 2 + 32 + 1][1] = gImage_p[j + 1];

                Display_PWM[a * 2 + i * 16 * 2 * 2][2] = gImage_p[j + 2];
                Display_PWM[a * 2 + i * 16 * 2 * 2 + 1][2] = gImage_p[j + 2];
                Display_PWM[a * 2 + i * 16 * 2 * 2 + 32][2] = gImage_p[j + 2];
                Display_PWM[a * 2 + i * 16 * 2 * 2 + 32 + 1][2] = gImage_p[j + 2];

                j += 3;
            }

        }


        rt_thread_mdelay (150);
//        rt_kprintf("PicCount %lu  total_point:%lu \n", PicCount, total_point);

        PicCount++;
        if (PicCount >= (total_point / 3 / 16 / 16) )
        {
            j = 0;
            PicCount = 0;
        }

        if(last_index == get_image_index())
            continue;

        j = 0;
        PicCount = 0;
        last_index = get_image_index();

        count++;
        if (count > IMAGE_MAX_COUNT)
            count = 1;

        switch (count)
        {
            case 1:
                total_point = sizeof (gImage_111);
                gImage_p = gImage_111;
                break;

            case 2:
                total_point = sizeof (gImage_222);
                gImage_p = gImage_222;
                break;

            case 3:
                total_point = sizeof (gImage_333);
                gImage_p = gImage_333;
                break;

            case 4:
                total_point = sizeof (gImage_444);
                gImage_p = gImage_444;
                break;

            case 5:
                total_point = sizeof (gImage_555);
                gImage_p = gImage_555;
                break;

            case 6:
                total_point = sizeof (gImage_666);
                gImage_p = gImage_666;
                break;

            case 7:
                total_point = sizeof (gImage_777);
                gImage_p = gImage_777;
                break;

            case 8:
                total_point = sizeof (gImage_888);
                gImage_p = gImage_888;
                break;

            case 9:
                total_point = sizeof (gImage_999);
                gImage_p = gImage_999;
                break;
        }

    }
}

#include "stdlib.h"

void Display_Demo3()
{
    uint8_t last_index = 0xff;

    while(get_demo_index() == 3)
    {
        rt_thread_mdelay(100);
        if(last_index == get_image_index())
            continue;

        last_index = get_image_index();
        srand(rt_tick_get());

            for (uint16_t a = 0; a < 1024; a++)
            {
                Display_PWM[a][0] = (rand() % 128);
                Display_PWM[a][1] = (rand() % 128);
                Display_PWM[a][2] = (rand() % 128);
            }
        }
    }
}

void LED_PWM_TEST()
{
    static uint8_t index = 0;

    for (uint16_t j = 0; j < 3; j++)
    {
        for (uint16_t i = 0; i < 32; i++)
        {
            for (uint16_t a = 0; a < 32; a++)
            {
                if(index == 0)
                {
                    Display_PWM[a + i * 32][0] = i * 8 + (a >> 2);
                    Display_PWM[a + i * 32][1] = 0;
                    Display_PWM[a + i * 32][2] = 0;
                }
                else if(index == 1)
                {
                    Display_PWM[a + i * 32][0] = i * 8 + (a >> 2);
                    Display_PWM[a + i * 32][1] = i * 8 + (a >> 2);
                    Display_PWM[a + i * 32][2] = 0;
                }
                else if(index == 2)
                {
                    Display_PWM[a + i * 32][0] = 0;
                    Display_PWM[a + i * 32][1] = i * 8 + (a >> 2);
                    Display_PWM[a + i * 32][2] = 0;
                }
                else if(index == 3)
                {
                    Display_PWM[a + i * 32][0] = 0;
                    Display_PWM[a + i * 32][1] = i * 8 + (a >> 2);
                    Display_PWM[a + i * 32][2] = i * 8 + (a >> 2);
                }
                else if(index == 4)
                {
                    Display_PWM[a + i * 32][0] = 0;
                    Display_PWM[a + i * 32][1] = 0;
                    Display_PWM[a + i * 32][2] = i * 8 + (a >> 2);
                }
                else if(index == 5)
                {
                    Display_PWM[a + i * 32][0] = i * 8 + (a >> 2);
                    Display_PWM[a + i * 32][1] = 0;
                    Display_PWM[a + i * 32][2] = i * 8 + (a >> 2);
                }

//                Display_PWM[a + i * 32][j] = rand() & 0xff;
//                rt_kprintf("%d\t",Display_PWM[a+i*32][0]);
            }

//            rt_kprintf("\r");
        }
    }

    uint16_t PWM_temp[8];
    static double y = 1;

    index++;

    if(index > 5)
    {
        index = 0;

        y += 0.005;

        for (uint8_t i = 0; i < 8; i++)
        {
            PWM_temp[i] = pow (0x01 << i, y) + 1;

//            rt_kprintf("%d ", PWM_temp[i]);
        }
//        rt_kprintf ("\r");
        set_led_gamma (PWM_temp);
    }
}
